计数排序:时间复杂度O(n+k),空间复杂度O(k)
- 问题描述
假设n个记录中每个关键字都介于0到k-1之间,修改计数排序算法,使得算法满足:
时间复杂度:O(n+k),空间复杂度:n+O(k)
- 问题分析
原计数排序算法中,需借助另一个大小为n的数组进行排序,不能做到原地排序,如何实现原地排序?
原计数排序算法中,对数组中的每个元素,都已计算出了比其小或相等的元素个数,即确定了其最终位置。每个元素都已确定了自身的最终位置,但如何实现原地排序?
- 解决思路
从数组最后一个元素array[array.size()-1]开始,将其交换至最终位置上,并对交换后的array[array.size()-1]继续执行此操作,直至该元素的最终位置即为此位置为止,此后,对下一个位置执行相同操作,直至执行至数组的第二个位置为止。
但存在一个问题,当数组存在相同元素时,若其中一个元素已在其最终位置A[j],当对另一个元素交换至其最终位置的过程中,发现其最终位置已存在与其相等的元素,此时,应将该元素交换至A[k]处,A[k]为从j往前的第一个不同于该元素的位置。
- 实现代码
C++实现,其中数组用vector<pair<int, int> >存储,pair的第一个元素为待排序元素,第二个元素为该元素的重复个数,用以确定该算法是否稳定。
1 void counting_sort(vector<pair<int, int> > &array, int k) { 2 vector<int> array_count(k, 0); 3 for (vector<pair<int, int> >::const_iterator iter = array.begin(); iter != array.end(); ++iter) 4 ++array_count[iter->first]; 5 for (size_t i = 1; i != array_count.size(); ++i) 6 array_count[i] += array_count[i-1]; 7 8 for (int i = array.size() -1; i != 0; --i) { 9 int j = array_count[array[i].first] - 1; 10 if (j != i) { 11 while (j >= 0 && j != i && array[j].first == array[i].first) --j; 12 if (j != i) { 13 if (j == -1) j = 0; 14 pair<int, int> temp = array[i]; 15 array[i] = array[j]; 16 array[j] = temp; 17 ++i; 18 } 19 } 20 } 21 }